/**
 * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "GPUImagePixelationFilter.h"

const std::string GPUImagePixelationFilter::PIXELATION_FRAGMENT_SHADER = R"(
    #extension GL_OES_EGL_image_external : require
    precision highp float;

    varying vec2 textureCoordinate;

    uniform float imageWidthFactor;
    uniform float imageHeightFactor;
    uniform samplerExternalOES inputImageTexture;
    uniform float pixel;

    void main()
    {
        vec2 uv  = textureCoordinate.xy;
        float dx = pixel * imageWidthFactor;
        float dy = pixel * imageHeightFactor;
        vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy));
        vec3 tc = texture2D(inputImageTexture, coord).xyz;
        gl_FragColor = vec4(tc, 1.0);
    }
)";

GPUImagePixelationFilter::GPUImagePixelationFilter()
    : GPUImageFilter(NO_FILTER_VERTEX_SHADER, PIXELATION_FRAGMENT_SHADER)
{
    pixel = 1.0f;
}

void GPUImagePixelationFilter::onInit()
{
    GPUImageFilter::onInit();
    imageWidthFactorLocation =
        glGetUniformLocation(getProgram(), "imageWidthFactor");
    imageHeightFactorLocation =
        glGetUniformLocation(getProgram(), "imageHeightFactor");
    pixelLocation = glGetUniformLocation(getProgram(), "pixel");
}

void GPUImagePixelationFilter::onInitialized()
{
    GPUImageFilter::onInitialized();
    setPixel(pixel);
}

void GPUImagePixelationFilter::onOutputSizeChanged(int width, int height)
{
    if (width == 0 || height == 0) {
        return;
    }
    GPUImageFilter::onOutputSizeChanged(width, height);
    setFloat(imageWidthFactorLocation, 1.0f / width);
    setFloat(imageHeightFactorLocation, 1.0f / height);
}

void GPUImagePixelationFilter::setPixel(float pixelValue)
{
    pixel = pixelValue;
    setFloat(pixelLocation, pixel);
}